//
//  CollectionViewController.swift
//  DemoProject
//
//  Created by hao on 2018/7/18.
//  Copyright © 2018年 hao. All rights reserved.
//
/// RxSwift tableview 和 collectionView 范例: http://www.hangge.com/blog/cache/category_72_4.html

import UIKit

// MARK: 自定义CollectionViewCell
fileprivate class MyCollectionViewCell: UICollectionViewCell {
    
    var label:UILabel!
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        //背景设为橙色
        self.backgroundColor = UIColor.orange
        
        //创建文本标签
        label = UILabel(frame: frame)
        label.textColor = UIColor.white
        label.textAlignment = .center
        self.contentView.addSubview(label)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        label.frame = bounds
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

// MARK: headview
fileprivate class MySectionHeaderView: UICollectionReusableView {
    var label:UILabel!
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        //背景设为黑色
        self.backgroundColor = UIColor.lightGray
        
        //创建文本标签
        label = UILabel(frame: frame)
        label.textColor = UIColor.black
        label.textAlignment = .center
        self.addSubview(label)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        label.frame = bounds
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

// MARK: 自定义Section
fileprivate struct MySection {
    var header: String
    var items: [Item]
}

extension MySection : AnimatableSectionModelType {
    typealias Item = String
    
    var identity: String {
        return header
    }
    
    init(original: MySection, items: [Item]) {
        self = original
        self.items = items
    }
}

class CollectionViewController: BaseTableViewController {

    let disposeBag = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupData()
        //定义布局方式以及单元格大小
        let flowLayout = UICollectionViewFlowLayout()
        flowLayout.itemSize = CGSize(width: 100, height: 70)
        // 设置headerView的尺寸大小
        flowLayout.headerReferenceSize = CGSize(width: self.tableHeadView.width, height: 40)
        
        let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: 0, height: 0), collectionViewLayout: flowLayout)
        self.tableHeadView.addSubview(collectionView)
        collectionView.size = self.tableHeadView.size
        collectionView.backgroundColor = UIColor.white
        collectionView.register(MyCollectionViewCell.self, forCellWithReuseIdentifier: "MyCollectionViewCell")
        collectionView.register(MySectionHeaderView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "MySectionHeaderView")
        
        // RxDataSources 绑定数据
//        _rxBindSectionData(collectionView)
        
        // 刷新或停止集合数据
        _rxRefreshData(collectionView)
        
        // 单元格事件响应
//        _rxPropertyEventResponse(collectionView)
        
        //设置代理
        collectionView.rx.setDelegate(self).disposed(by: disposeBag)
    }
    
    // 刷新集合数据
    private func _rxRefreshData(_ collectionView: UICollectionView) {
        let refresh = UIBarButtonItem()
        refresh.title = "刷新"
        let stop = UIBarButtonItem()
        stop.title = "停止"
        navigationItem.rightBarButtonItems = [refresh, stop]
        
        //随机的表格数据
        let randomResult = refresh.rx.tap.asObservable()
//            .throttle(1, scheduler: MainScheduler.instance) //在主线程中操作，1秒内值若多次改变，取最后一次
            .startWith(()) //加这个为了让一开始就能自动请求一次数据
            .flatMapLatest { [weak self] _ -> Observable<[SectionModel<String, Int>]> in // 连续请求时只取最后一次数据  // 或者 flatMapFirst: 连续请求时只取第一次数据
                // takeUntil 操作符可以监视另外一个 Observable， 即 notifier
                // 如果 notifier 发出值或 complete 通知，那么源 Observable 便自动完成，停止发送事件
                self!.getRandomResult().takeUntil(stop.rx.tap)
            }
            .share(replay: 1)
        
        //创建数据源
        let dataSource = RxCollectionViewSectionedReloadDataSource
            <SectionModel<String, Int>>(
                configureCell: { (dataSource, collectionView, indexPath, element) in
                    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCollectionViewCell",
                                                                  for: indexPath) as! MyCollectionViewCell
                    cell.label.text = "\(element)"
                    return cell
            }
        )
        randomResult.bind(to: collectionView.rx.items(dataSource: dataSource)).disposed(by: disposeBag)
    }
    
    // RxDataSources 绑定数据
    private func _rxBindSectionData(_ collectionView: UICollectionView) {
        //初始化数据
        let sections = Observable.just([
            MySection(header: "脚本语言", items: [
                "Python",
                "javascript",
                "PHP",
                ]),
            MySection(header: "高级语言", items: [
                "Swift",
                "C++",
                "Java",
                "C#"
                ])
            ])
        
        //创建数据源
        let dataSource = RxCollectionViewSectionedReloadDataSource<MySection>(
            configureCell: { (dataSource, collectionView, indexPath, element) in
                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCollectionViewCell",
                                                              for: indexPath) as! MyCollectionViewCell
                cell.label.text = "\(element)"
                return cell},
            configureSupplementaryView: {
                (ds ,cv, kind, ip) in
                let section = cv.dequeueReusableSupplementaryView(ofKind: kind,
                                                                  withReuseIdentifier: "MySectionHeaderView", for: ip) as! MySectionHeaderView
                section.label.text = "\(ds[ip.section].header)"
                return section
        })
        
        //绑定单元格数据
        sections.bind(to: collectionView.rx.items(dataSource: dataSource)).disposed(by: disposeBag)
    }
    
    // 单元格事件响应
    private func _rxPropertyEventResponse(_ collectionView: UICollectionView) {
        //获取选中项的索引
        collectionView.rx.itemSelected.subscribe(onNext: { indexPath in
            print(info: "选中项的indexPath为：\(indexPath)")
        }).disposed(by: disposeBag)
        
        //获取选中项的内容
        collectionView.rx.modelSelected(String.self).subscribe(onNext: { item in
            print(info: "选中项的标题为：\(item)")
        }).disposed(by: disposeBag)
        
        // 同时获取选中项和索引
//        Observable.zip(collectionView.rx.itemSelected, collectionView.rx.modelSelected(String.self))
//            .bind { [weak self] indexPath, item in
//                self?.showMessage("选中项的indexPath为：\(indexPath)")
//                self?.showMessage("选中项的标题为：\(item)")
//            }
//            .disposed(by: disposeBag)
        
        //获取被取消选中项的索引
        collectionView.rx.itemDeselected.subscribe(onNext: { indexPath in
            print(info: "被取消选中项的indexPath为：\(indexPath)")
        }).disposed(by: disposeBag)
        
        //获取被取消选中项的内容
        collectionView.rx.modelDeselected(String.self).subscribe(onNext: { item in
            print(info: "被取消选中项的的标题为：\(item)")
        }).disposed(by: disposeBag)
        
        // 合并单元格取消选中事件响应
        Observable
            .zip(collectionView.rx.itemDeselected, collectionView.rx.modelDeselected(String.self))
            .bind { indexPath, item in
                print(info: "被取消选中项的indexPath为：\(indexPath)")
                print(info: "被取消选中项的的标题为：\(item)")
            }
            .disposed(by: disposeBag)
        
        //获取选中并高亮完成后的索引
        collectionView.rx.itemHighlighted.subscribe(onNext: { indexPath in
            print(info: "高亮单元格的indexPath为：\(indexPath)")
        }).disposed(by: disposeBag)
        
        //获取高亮转成非高亮完成后的索引
        collectionView.rx.itemUnhighlighted.subscribe(onNext: { indexPath in
            print(info: "失去高亮的单元格的indexPath为：\(indexPath)")
        }).disposed(by: disposeBag)
        
        //单元格将要显示出来的事件响应
        collectionView.rx.willDisplayCell.subscribe(onNext: { cell, indexPath in
            print(info: "将要显示单元格indexPath为：\(indexPath)")
            print(info: "将要显示单元格cell为：\(cell)\n")
        }).disposed(by: disposeBag)
        
        //分区头部、尾部将要显示出来的事件响应
        collectionView.rx.willDisplaySupplementaryView.subscribe(onNext: { view, kind, indexPath in
            print(info: "将要显示分区indexPath为：\(indexPath)")
            print(info: "将要显示的是头部还是尾部：\(kind)")
            print(info: "将要显示头部或尾部视图：\(view)\n")
        }).disposed(by: disposeBag)
    }

    //获取随机数据
    private func getRandomResult() -> Observable<[SectionModel<String, Int>]> {
        print(info: "正在请求数据......")
        let items = (0 ..< 5).map {_ in
            Int(arc4random_uniform(100000))
        }
        let observable = Observable.just([SectionModel(model: "S", items: items)])
        return observable.delay(2, scheduler: MainScheduler.instance)
    }
    
    private func setupData() {
        let titles = ["collectionViewLayout",
                      "backgroundView",
                      "allowsSelection",
                      "allowsMultipleSelection",
                      "注册和获取cell",
                      "UICollectionView视图布局方法",
                      "增删查改Cell",
                      "设置布局"]
        
        let descArr = ["设置子视图的布局方式",
                       "设置UICollectionView的背景视图",
                       "设置 UICollectionView 的 Cell 是否可以点击",
                       "设置 UICollectionView 的 Cell 是否可以多选",
                       """
                        // 1.设置UICollectionView的注册类, 以及标示符
                        func registerClass(cellClass: AnyClass?, forCellWithReuseIdentifier identifier: String)

                        // 2.设置 UICollectionView的注册Nib, 以及标示符
                        func registerNib(nib: UINib?, forCellWithReuseIdentifier identifier: String)

                        // 3.设置 UICollectionView 的注册类, 以及辅助视图名称, 标示符
                        func registerClass(viewClass: AnyClass?, forSupplementaryViewOfKind elementKind: String, withReuseIdentifier identifier: String)

                        // 4.设置 UICollectionView的注册Nib, 以及辅助视图名称, 标示符
                        func registerNib(nib: UINib?, forSupplementaryViewOfKind kind: String, withReuseIdentifier identifier: String)

                        // 5.设置 UICollectionView 可重用的 Cell 以及所以路径
                        func dequeueReusableCellWithReuseIdentifier(identifier: String, forIndexPath indexPath: NSIndexPath!) -> AnyObject

                        // 6.设置 UICollectionView 可重用的的辅视图, 标示符, 以及索引路径
                        func dequeueReusableSupplementaryViewOfKind(elementKind: String, withReuseIdentifier identifier: String, forIndexPath indexPath: NSIndexPath!) -> AnyObject
                       """,
                       """
                        // 1.该方法是用来设置 UICollectionView 的 Item 尺寸大小
                        optional func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize
                       
                        // 2.该方法是用来设置 UICollectionView 的 Item 四周的边界
                        optional func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets
                       
                        // 3.该方法是用来设置 UICollectionView 的 Item 上下之间的最小间距(如果在自定义UICollectionView中实现了该属性, 那么该方法就会覆盖掉原来的属性)
                        optional func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat
                       
                        // 4.该方法是用来设置 UICollectionView 的 Item 左右之间的最小间距(如果在自定义UICollectionView中实现了该属性, 那么该方法就会覆盖掉原来的属性)
                        optional func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat
                       
                        // 5.该方法是用来设置 UICollectionView 的页头尺寸(如果在自定义UICollectionView中实现了该属性, 那么该方法就会覆盖掉原来的属性)
                        optional func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize
                       
                        // 6.该方法是用来设置 UIcollectionView 的页尾尺寸(如果在自定义UICollectionView中实现了该属性, 那么该方法就会覆盖掉原来的属性)
                        optional func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize
                       """,
                       """
                        // 1.设置 UICollectionView 滚动到第几个 Item 的索引路径, 以及显示样式和是否启用动画
                        func scrollToItemAtIndexPath(indexPath: NSIndexPath, atScrollPosition scrollPosition: UICollectionViewScrollPosition, animated: Bool)
                         
                        // 2.在 UICollectionView 中插入某个 Item
                        func insertSections(sections: NSIndexSet)
                        
                        // 3.在 UICollectionView 中删除某个 Item
                        func deleteSections(sections: NSIndexSet)
                         
                        // 4.在 UICollectionView 中刷新某个 Item
                        func reloadSections(sections: NSIndexSet)
                        
                        // 5.移动 UICollectionView 中某个 Item 到某个位置
                        func moveSection(section: Int, toSection newSection: Int)
                       """,
                       """
                        // 1.设置 UICollectionView 的集合视图布局, 及是否使用动画
                        func setCollectionViewLayout(layout: UICollectionViewLayout, animated: Bool)
                        
                        // 2.设置 UICollectionView 的集合视图布局, 及是否使用动画, 以及完成之后的闭包方法
                        func setCollectionViewLayout(layout: UICollectionViewLayout, animated: Bool, completion: ((Bool) -> Void)!)
                       """]
        
        addTitles(titles, footDescs: descArr)
    }

}

// MARK: collectionView代理实现
extension CollectionViewController: UICollectionViewDelegateFlowLayout {
    
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> CGSize {
        let width = collectionView.bounds.width
        let cellWidth = (width - 30) / 4 //每行显示4个单元格
        return CGSize(width: cellWidth, height: cellWidth * 1.5) //单元格宽度为高度1.5倍
    }
    
}


